package com.gitee.hermer.engine.jars.starter.web.api;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
import java.io.InputStream;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Date;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationEventPublisher;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.commons.CommonsMultipartFile;

import com.gitee.hermer.boot.jee.commons.collection.CollectionUtils;
import com.gitee.hermer.boot.jee.commons.collection.StringCache;
import com.gitee.hermer.boot.jee.commons.encrypt.Md5Utils;
import com.gitee.hermer.boot.jee.commons.log.UtilsContext;
import com.gitee.hermer.boot.jee.commons.utils.FileUtils;
import com.gitee.hermer.boot.jee.commons.utils.JarUtils;
import com.gitee.hermer.boot.jee.commons.utils.StringUtils;
import com.gitee.hermer.engine.jars.app.sdk.EngineAppClassLoader;
import com.gitee.hermer.engine.jars.core.context.IEngineAppContext;
import com.gitee.hermer.engine.jars.core.domain.BaseInfo;
import com.gitee.hermer.engine.jars.core.domain.EngineConstant;
import com.gitee.hermer.engine.jars.core.loader.EngineAppBeanScanner;
import com.gitee.hermer.engine.jars.core.loader.IEngineAppClassLoaderCacheMap;
import com.gitee.hermer.engine.jars.core.loader.event.EngineAppDestroyEvent;
import com.gitee.hermer.engine.jars.core.loader.event.EngineAppInitializationEvent;
import com.gitee.hermer.engine.jars.starter.web.base.BaseControllerHandler;

@RestController
@RequestMapping("api/execute-deploy")
public class EngineApiDeployController extends BaseControllerHandler implements ApplicationEventPublisherAware{

	@Autowired
	private IEngineAppContext appContext;

	private ApplicationEventPublisher eventPublisher;

	@Autowired
	private IEngineAppClassLoaderCacheMap appClassLoaderCacheMap;
	
	private final int OLD_BACKUPS_FILE_SIZE = 5;

	@Override
	public void setApplicationEventPublisher(ApplicationEventPublisher applicationEventPublisher) {
		this.eventPublisher = applicationEventPublisher;
	}


	@RequestMapping(value="file/ci-upload",method=RequestMethod.POST)
	@ResponseBody
	public BaseInfo<String> ciDeploy(@RequestParam("file") CommonsMultipartFile[] files,HttpServletRequest request) throws Exception{
		for(int i = 0;i<files.length;i++){  
			info("正在上传文件[%s]",files[i].getOriginalFilename());
			final File temp = saveTempFile(files, i);
			final EngineAppInitializationEvent event = EngineAppBeanScanner.createEngineAppInitializationEvent(temp);

			if(appContext.getCurrentLoaderState(event.getCacheKey()) != null){
				// stop now()
				EngineAppClassLoader classLoader = appClassLoaderCacheMap.get(event.getCacheKey());
				eventPublisher.publishEvent(new EngineAppDestroyEvent(event.getCacheKey(),classLoader));
				int l = 0;
				while (!classLoader.isClose() && l < 5) {
					l += 1;
					Thread.sleep(1000l);
				}
			}
			String md5 = StringUtils.toHexString(Md5Utils.md5(FileUtils.readBytes(temp)));

			final String jarFileName = files[i].getOriginalFilename();

			File tempDir = JarUtils.createTempDirectory();
			info("正在解压至 -> [%s]",tempDir.getPath());
			JarUtils.unJar(temp, tempDir);
			File resources = FileUtils.file(tempDir, "resources");
			File deployFile = null;
			if(resources.exists()){
				deployFile = new File(FileUtils.getAbsolutePath("../../"));
				info("更新部署中 -> 替换静态资源文件 -> 替换地址[%s]",deployFile.getPath());
				FileUtils.copy(resources, deployFile, true);
			}

			String WEB_INF = FileUtils.getAbsolutePath(new StringCache("../").toString());

			File workBackup = new File(new StringCache(WEB_INF).append(EngineConstant.FILE_NAME_ENGINE_WORK_JAR_BACKUP).toString());
			File workJars = new File(new StringCache(WEB_INF).append(EngineConstant.FILE_NAME_ENGINE_WORK_JAR).toString());

			if(FileUtils.file(workJars, jarFileName).exists()){
				if(!workBackup.exists()){
					workBackup.mkdirs();
				}
				List<File> backups = CollectionUtils.newArrayList(workBackup.listFiles(new FilenameFilter() {
					@Override
					public boolean accept(File dir, String name) {
						return name.indexOf(new StringCache(jarFileName).append(StringUtils.DOT).append(EngineConstant.FILE_TYPE_BACKUPS).toString()) != -1;
					}
				}));
				CollectionUtils.sort(backups, new Comparator<File>(){
					@Override
					public int compare(File o1, File o2) {
						// TODO Auto-generated method stub
						return Long.valueOf(o1.lastModified()).compareTo(o2.lastModified());
					}
				});

				if(backups.size() >= OLD_BACKUPS_FILE_SIZE){
					List<File> removes = backups.subList(0, backups.size()-(OLD_BACKUPS_FILE_SIZE-1));
					for (File file : removes) {
						FileUtils.del(file);
					}
				}
				deployFile = FileUtils.file(workBackup, new StringCache(jarFileName).append(StringUtils.DOT).append(EngineConstant.FILE_TYPE_BACKUPS).append(new Date().getTime()).toString());
				info("更新部署中 -> 备份容器JAR文件 -> 地址[%s]",deployFile.getPath());
				FileUtils.copy(FileUtils.file(workJars, jarFileName), deployFile, true);
			}


			deployFile = FileUtils.file(workJars, jarFileName+".md5");
			info("更新部署中 -> 替换模块MD5文件[%s] -> 内容-> [%s]",deployFile.getPath(),md5);
			FileUtils.write(deployFile.getPath(), md5);
			deployFile = FileUtils.file(workJars, jarFileName);

			info("更新部署中 -> 替换容器JAR文件 -> 替换地址[%s]",deployFile.getPath());
			FileUtils.copy(temp, deployFile, true);
			eventPublisher.publishEvent(EngineAppBeanScanner.createEngineAppInitializationEvent(deployFile));
		}
		return new BaseInfo<String>("","上传成功！");
	}

	private File saveTempFile(CommonsMultipartFile[] files, int i) throws IOException, FileNotFoundException {
		File temp = File.createTempFile(new Date().getTime()+"", ".jar");
		info("服务器存根地址 -> [%s]",temp.getPath());
		FileUtils.writeFromStream(files[i].getInputStream(), temp);
		return temp;
	}



}
